#include <stdlib.h>
#include <stdio.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <string>
using namespace std;

#include "TetrisPieces.h"
#include "Button.h"

//Define Screen info
#define SCREEN_WIDTH	640
#define SCREEN_HEIGHT	480
#define DEPTH		32
Uint32 videoFlags = SDL_SWSURFACE;

//Define Sprite info
#define SPRITE_WIDTH	24
#define SPRITE_HEIGHT	24

//Define size of the board
#define ROWS_OF_BOARD	20
#define COLS_OF_BOARD	10

//define total levels
#define NUMBER_OF_LVLS	10

//Define Colision infoh
#define LEFT_WALL	200
#define RIGHT_WALL	416
#define TOP_WALL	0
#define BOTTOM_WALL	456

//Define the size of Number and Level
#define NUMBER_WIDTH	50
#define NUMBER_HEIGHT	80
#define LEVEL_WIDTH		200
#define LEVEL_HEIGHT	150

//Define middle coordinates of Score board and Level board
#define SCORE_X	25
#define SCORE_Y	200
#define LEVEL_X	50
#define LEVEL_Y	370

//Define Color of Sprite (for random choice)
#define GRID	-1
#define RED		0
#define BLUE	1
#define GREEN	2
#define PINK	3
#define YELLOW	4
#define WHITEBLUE	5
#define ORANGE	6
#define NUMBER_OF_COLORS  7
#define NUMBER_OF_PIECE_TYPES  7

//Coordinates of LevelChange Sign
#define LEVELSIGN_X	220
#define LEVELSIGN_Y	165

//Coordinates of GameOver
#define GAMEOVER_X	70
#define GAMEOVER_Y	80	

//Coordinates of Pause
#define PAUSE_X	145
#define PAUSE_Y	90

//Button's Attributes
#define BUTTON_NEW_GAME_X	480
#define BUTTON_NEW_GAME_Y	250
#define BUTTON_NEW_GAME_W	130
#define BUTTON_NEW_GAME_H	41
#define BUTTON_EXIT_GAME_X	480
#define BUTTON_EXIT_GAME_Y	400
#define BUTTON_EXIT_GAME_W	130
#define BUTTON_EXIT_GAME_H	41
#define BUTTON_PAUSE_GAME_X 480
#define BUTTON_PAUSE_GAME_Y	300
#define BUTTON_PAUSE_GAME_W	130
#define BUTTON_PAUSE_GAME_H	41
#define BUTTON_SOUND_X	480
#define BUTTON_SOUND_Y	350
#define BUTTON_SOUND_W	130
#define BUTTON_SOUND_H	41

//Define SDL Surfaces
SDL_Surface *screen = NULL;
SDL_Surface *background[NUMBER_OF_LVLS] = {NULL};
SDL_Surface *starAtFullRow = NULL;
SDL_RWops *rwopStarAtFullRow = NULL;
SDL_Surface *spriteColor[NUMBER_OF_COLORS] = {NULL};
SDL_Surface *spriteGrid = NULL;
SDL_Surface *numberB[NUMBER_OF_LVLS] = {NULL};
SDL_Surface *numberR[NUMBER_OF_LVLS] = {NULL};
SDL_Surface *level[NUMBER_OF_LVLS] = {NULL};
SDL_RWops *rwopBNumber[NUMBER_OF_LVLS] = {NULL};
SDL_RWops *rwopRNumber[NUMBER_OF_LVLS] = {NULL};
SDL_RWops *rwopLevel[NUMBER_OF_LVLS] = {NULL};
SDL_Surface *spriteGameOver = NULL;
SDL_RWops *rwopGameOver = NULL;
SDL_Surface *spritePause = NULL;
SDL_RWops *rwopPause = NULL;

//Define running bool check
bool tetrisRunning = true;
bool gameOver = false;
bool gamePause = false;
bool isRowCuttable = false;
//Define event control var
SDL_Event event;

//Define coordinates var of sprite
int srcX = 0;
int srcY = 0;
int readyDstX = 520;
int readyDstY = 130;
int dstX = 320;
int dstY = 0;

//Save coordinates of the current piece
int pCoordinate[4][2] = {0};
int nextPieceCoordinate[4][2] = {0};

//Define Mul-Array of Pieces info
TetrisPieces *mPieces;
//Define type, state and color of the ready piece
int readyPieceType;
int readyPieceRotation;
int readyieceColor;
//Define type, state and color of the current piece
int mPieceType;
int mPieceRotation;
int mColor;
//Define timer variable
int fpsClock;
int startClock = 0;
int checkClock = 0;
//Check if a new piece is spawned
bool spawnable = false;

//Define board to store color of sprite
int board[ROWS_OF_BOARD][COLS_OF_BOARD];
int scoreBoard[3];
int levelCheckBoard[2];

//Define var to save the score and level
int mScore;
int mLevel;

//Define sound effects
Mix_Music *theme= NULL;
Mix_Chunk *scratch= NULL;
Mix_Chunk *turn= NULL;
int isMute;

//Define bool var to check Level if change
bool isLevelChange = false;

//Define delay time
int delayTime = 600;
//Frame limit
const int FRAMES_PER_SECOND = 30;

//Define button
Button *buttonNewGame;
SDL_Surface *spriteButtonNewGame = NULL;
SDL_RWops *rwopButtonNewGame = NULL;
Button *buttonExitGame;
SDL_Surface *spriteButtonExitGame = NULL;
SDL_RWops *rwopButtonExitGame = NULL;
Button *buttonPauseGame;
SDL_Surface *spriteButtonPauseGame = NULL;
SDL_RWops *rwopButtonPauseGame = NULL;
Button *buttonSound;
SDL_Surface *spriteButtonSound = NULL;
SDL_RWops *rwopButtonSound = NULL;

/**
 *Function: convertInt
 *Purpose: convert a given integer to string
 *Var: int: number being processed
 *Return: string of the integer
 **/
string convertInt(int number)
{
    if (number == 0) return "0";

    string temp = "";
    string returnvalue = "";
    while (number > 0)
    {
        temp += number%10 + 48;
        number /= 10;
    }
    for (int i = 0; i < temp.length(); i++)
        returnvalue += temp[temp.length() - i - 1];

    return returnvalue;
}

/**
 *Function: randomChoice
 *Purpose: choose a random number from 0 to divNum
 *Var: -divNum: Max limit of random return
 *Return: int
 **/
int randomChoice (int divNum){
	int tmp = rand();
	return (tmp)% divNum;
}

/**
 *Function: init
 *Purpose: - init Everything in SDL
 *         - Change the Title of Program to "BK Tetris"
 *         - Put icon to Program
 *         - Init the board
 *		   - Load surfaces.
 *         - Init the score and level
 *Var: nothing
 *Return:true if succes, false if not
 **/
bool init(){
	//Init SDL
	SDL_Init(SDL_INIT_EVERYTHING);

	//Update the Title
	SDL_WM_SetCaption("BK Tetris",NULL);

	//Setup the Icon
	SDL_Surface *icon = SDL_LoadBMP("icon.bmp");
	SDL_WM_SetIcon(icon, NULL);

	//Load the screen
	screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,DEPTH,videoFlags);

	//Load the Background Picture
	background[0] = SDL_LoadBMP("background01.bmp");
	background[1] = SDL_LoadBMP("background02.bmp");
	background[2] = SDL_LoadBMP("background03.bmp");
	background[3] = SDL_LoadBMP("background04.bmp");
	background[4] = SDL_LoadBMP("background05.bmp");
	background[5] = SDL_LoadBMP("background06.bmp");
	background[6] = SDL_LoadBMP("background07.bmp");
	background[7] = SDL_LoadBMP("background08.bmp");
	background[8] = SDL_LoadBMP("background09.bmp");
	background[9] = SDL_LoadBMP("background10.bmp");

	//Load the star image
	rwopStarAtFullRow = SDL_RWFromFile("FullRow.png","rb");
	//starAtFullRow = SDL_LoadBMP("stars.bmp");
	starAtFullRow = IMG_LoadPNG_RW(rwopStarAtFullRow);

	//Init the board
	for (int i = 0; i < ROWS_OF_BOARD; i++){
		for (int j = 0; j < COLS_OF_BOARD; j++){
			board[i][j] = -1;
		}
	}

	//Init the score board:
	scoreBoard[0]=0;
	scoreBoard[1]=0;
	scoreBoard[2]=0;

	//Init the level board:
	levelCheckBoard[0]=0;
	levelCheckBoard[1]=1;

	//Init First Pieces
	mPieceType = randomChoice(NUMBER_OF_PIECE_TYPES);
	mPieceRotation = randomChoice(4); 
	mColor = randomChoice(NUMBER_OF_COLORS);

	//Load a sprite
	spriteColor[0] = SDL_LoadBMP("sprite_Red.bmp");
	spriteColor[1] = SDL_LoadBMP("sprite_Blue.bmp");
	spriteColor[2] = SDL_LoadBMP("sprite_Green.bmp");
	spriteColor[3] = SDL_LoadBMP("sprite_Pink.bmp");
	spriteColor[4] = SDL_LoadBMP("sprite_Yellow.bmp");
	spriteColor[5] = SDL_LoadBMP("sprite_WhiteBlue.bmp");
	spriteColor[6] = SDL_LoadBMP("sprite_Orange.bmp");
	spriteGrid = SDL_LoadBMP("sprite_Grid.bmp");

	//Load number files 
	string fileName = "";
	string lvlToString = "";
	string typeOfFile = ".png";
	const char* fileNamePtr;

	for (int i = 0; i < NUMBER_OF_LVLS; i++) {
		lvlToString = convertInt(i);
		fileName = lvlToString + typeOfFile;
		fileNamePtr = fileName.c_str();
		rwopBNumber[i] = SDL_RWFromFile(fileNamePtr,"rb");

		fileName = "r" + lvlToString + typeOfFile;
		fileNamePtr = fileName.c_str();
		rwopRNumber[i] = SDL_RWFromFile(fileNamePtr,"rb");
	}

	//Load level files
	for (int i = 0; i <= NUMBER_OF_LVLS; i++) {
		lvlToString = convertInt(i);
		fileName = "Level_" + lvlToString + typeOfFile;
		fileNamePtr = fileName.c_str();
		rwopLevel[i] = SDL_RWFromFile(fileNamePtr,"rb");
	}

	//Convert SDL RWOP to Surface
	for (int i = 0; i < NUMBER_OF_LVLS; i++){
		numberB[i] = IMG_LoadPNG_RW(rwopBNumber[i]);
		numberR[i] = IMG_LoadPNG_RW(rwopRNumber[i]);
		level[i] = IMG_LoadPNG_RW(rwopLevel[i]);
	}

	//Load GameOver iMage
	rwopGameOver = SDL_RWFromFile("GameOver.png","rb");
	spriteGameOver = IMG_LoadPNG_RW(rwopGameOver);

	//Load Pause iMage
	rwopPause = SDL_RWFromFile("Pause.png","rb");
	spritePause = IMG_LoadPNG_RW(rwopPause);

	//Init the score and level
	mScore = 0;
	mLevel = 1;

	//Init SDL_mixer 
	Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 );

	//Load sound effects
	theme = Mix_LoadMUS("theme.wav");
	scratch = Mix_LoadWAV("scratch.wav");
	turn = Mix_LoadWAV("turn.wav");
	isMute = false;

	//Init Button
	buttonNewGame= new Button(BUTTON_NEW_GAME_X,BUTTON_NEW_GAME_Y,BUTTON_NEW_GAME_W,BUTTON_NEW_GAME_H);
	rwopButtonNewGame = SDL_RWFromFile("bNewGame.png","rb");
	spriteButtonNewGame = IMG_LoadPNG_RW(rwopButtonNewGame);
	buttonExitGame= new Button(BUTTON_EXIT_GAME_X,BUTTON_EXIT_GAME_Y,BUTTON_EXIT_GAME_W,BUTTON_EXIT_GAME_H);
	rwopButtonExitGame = SDL_RWFromFile("bExit.png","rb");
	spriteButtonExitGame = IMG_LoadPNG_RW(rwopButtonExitGame);
	buttonPauseGame= new Button(BUTTON_PAUSE_GAME_X,BUTTON_PAUSE_GAME_Y,BUTTON_PAUSE_GAME_W,BUTTON_PAUSE_GAME_H);
	rwopButtonPauseGame = SDL_RWFromFile("bPause.png","rb");
	spriteButtonPauseGame = IMG_LoadPNG_RW(rwopButtonPauseGame);
	buttonSound= new Button(BUTTON_SOUND_X,BUTTON_SOUND_Y,BUTTON_SOUND_W,BUTTON_SOUND_H);
	rwopButtonSound = SDL_RWFromFile("bMute.png","rb");
	spriteButtonSound = IMG_LoadPNG_RW(rwopButtonSound);

	return true;
}

/**
 *Function: cleanup()
 *Purpose: clean memory
 *Var:nothing
 *Return: void
 **/
void cleanup(){
	SDL_FreeSurface (screen);
	for (int i = 0; i < NUMBER_OF_LVLS; i++){
		SDL_FreeSurface (background[i]);
	}
	SDL_FreeSurface (starAtFullRow);
	SDL_FreeSurface (spriteGrid);
	SDL_FreeSurface (spritePause);
	SDL_FreeSurface (spriteGameOver);
	SDL_FreeSurface (spriteButtonNewGame);
	SDL_FreeSurface (spriteButtonExitGame);
	SDL_FreeSurface (spriteButtonPauseGame);
	SDL_FreeSurface (spriteButtonSound);
	for (int i = 0; i < NUMBER_OF_COLORS; i++){
		SDL_FreeSurface (spriteColor[i]);
	}
	for (int i = 0; i < NUMBER_OF_LVLS; i++){
		SDL_FreeSurface (numberB[i]);
		SDL_FreeSurface (numberR[i]);
		SDL_FreeSurface (level[i]);
	}
	Mix_FreeChunk(scratch);
	Mix_FreeChunk(turn);
	Mix_FreeMusic(theme);
	Mix_CloseAudio(); 
}

/**
 *Function: drawStaticImage
 *Purpose: show an Static image to Windows
 *Var:
 *-- x: X coordinate of image
 *-- y: Y coordinate of image
 *-- source: source surface 
 *-- destination: dst surface
 *Return: void
 **/

void drawStaticImage (int x, int y, 
				   SDL_Surface *source, SDL_Surface *destination){
	SDL_Rect rect;
	rect.x = x;
	rect.y = y;

	SDL_BlitSurface(source,NULL,destination,&rect);
}

/**
 *Function: drawSprite
 *Purpose: show an sprite image upper screen
 *Var:
 *-- srcX: X coordinate of src sprite image
 *-- srcY: Y coordinate of src sprite image
 *-- dstX: X coordinate of dst sprite image
 *-- dstY: Y coordinate of dst sprite image
 *-- width: the width of the sprite
 *-- height: the height of the sprite
 *-- source: source surface 
 *-- destination: dst surface
 *Return:void
 **/
void drawSprite(int srcX, int srcY, 
				int dstX, int dstY, 
				int width, int height,
				SDL_Surface *source, SDL_Surface *destination){
	SDL_Rect srcRect;
	SDL_Rect dstRect;

	srcRect.x = srcX;
	srcRect.y = srcY;
	srcRect.w = width;
	srcRect.h = height;

	dstRect.x = dstX;
	dstRect.y = dstY;
	dstRect.w = width;
	dstRect.h = height;

	SDL_BlitSurface(source,&srcRect,destination,&dstRect);

}

/**
 *Function: drawPieces
 *Purpose: show 4 sprite image upper screen to create a piece
 *Var:
 *-- srcX: X coordinate of src sprite image
 *-- srcY: Y coordinate of src sprite image
 *-- dstX: X coordinate of dst sprite image
 *-- dstY: Y coordinate of dst sprite image
 *-- width: the width of the sprite
 *-- height: the height of the sprite
 *-- source: source surface 
 *-- destination: dst surface
 *-- pPiece: Type of Piece (0,1,2,3,4,5,6)
 *-- pRotation: Type of Piece Rotation (0,1,2,3)
 *Return:void
 **/
void drawPieces (int srcX, int srcY, 
				int dstX, int dstY, 
				int width, int height,
				SDL_Surface *source, SDL_Surface *destination,
				int pPiece, int pRotation){
	int tmp = 0;
	for (int i = 0; i < 5; i++){
		for (int j = 0; j < 5; j++){
			if (mPieces->GetBlockType (pPiece, pRotation, j, i) ==1){
				int pdstX = dstX;
				int pdstY = dstY;
				int mx = i - 2;
				int my = j - 2;
				switch (mx){
					case -2:
						pdstX = dstX - 2*SPRITE_WIDTH;
						break;
					case -1:
						pdstX = dstX - SPRITE_WIDTH;
						break;
					case 0:
						break;
					case 1:
						pdstX = dstX + SPRITE_WIDTH;
						break;
					case 2:
						pdstX = dstX + 2*SPRITE_WIDTH;
						break;
				}
				switch (my){
					case -2:
						pdstY = dstY - 2*SPRITE_HEIGHT;
						break;
					case -1:
						pdstY = dstY - SPRITE_HEIGHT;
						break;
					case 0:
						break;
					case 1:
						pdstY = dstY + SPRITE_HEIGHT;
						break;
					case 2: 
						pdstY = dstY + 2*SPRITE_HEIGHT;
						break;
				}
				drawSprite(srcX,srcY,pdstX,pdstY,width,height,source,destination);

				//Save sprite info
				pCoordinate[tmp][0] = pdstX;
				pCoordinate[tmp][1] = pdstY;
				tmp++;
			}else if (mPieces->GetBlockType (pPiece, pRotation, j, i) == 2){
				drawSprite(srcX,srcY,dstX,dstY,width,height,source,destination);
				//Save sprite info
				pCoordinate[tmp][0] = dstX;
				pCoordinate[tmp][1] = dstY;
				tmp++;
			}
		}
	}
}

/**
 *Function: saveCoordinateOfNextPiece
 *Purpose: save 4 sprite image upper screen to create a piece
 *Var:
 *-- dstX: X coordinate of dst sprite image
 *-- dstY: Y coordinate of dst sprite image
 *-- pPiece: Type of Piece (0,1,2,3,4,5,6)
 *-- pRotation: Type of Piece Rotation (0,1,2,3)
 *Return:void
 **/
void saveCoordinateOfNextPiece (int dstX, int dstY, 
				int pPiece, int pRotation){
	int tmp = 0;
	for (int i = 0; i < 5; i++){
		for (int j = 0; j < 5; j++){
			if (mPieces->GetBlockType (pPiece, pRotation, j, i) ==1){
				int pdstX = dstX;
				int pdstY = dstY;
				int mx = i - 2;
				int my = j - 2;
				switch (mx){
					case -2:
						pdstX = dstX - 2*SPRITE_WIDTH;
						break;
					case -1:
						pdstX = dstX - SPRITE_WIDTH;
						break;
					case 0:
						break;
					case 1:
						pdstX = dstX + SPRITE_WIDTH;
						break;
					case 2:
						pdstX = dstX + 2*SPRITE_WIDTH;
						break;
				}
				switch (my){
					case -2:
						pdstY = dstY - 2*SPRITE_HEIGHT;
						break;
					case -1:
						pdstY = dstY - SPRITE_HEIGHT;
						break;
					case 0:
						break;
					case 1:
						pdstY = dstY + SPRITE_HEIGHT;
						break;
					case 2: 
						pdstY = dstY + 2*SPRITE_HEIGHT;
						break;
				}

				//Save sprite info
				nextPieceCoordinate[tmp][0] = pdstX;
				nextPieceCoordinate[tmp][1] = pdstY;
				tmp++;
			}else if (mPieces->GetBlockType (pPiece, pRotation, j, i) == 2){
				//Save sprite info
				nextPieceCoordinate[tmp][0] = dstX;
				nextPieceCoordinate[tmp][1] = dstY;
				tmp++;
			}
		}
	}
}

/**
 *Function: isAbleToSpawn
 *Purpose: check if the next piece can spawn
 *Var: int: displacement
 *Return: true if success, otherwise return false
 **/
bool isAbleToSpawn(int displacement) {
	bool moveable = true;
	int x,y;

	for (int i = 0; i < 4; i++) {
		y = (nextPieceCoordinate[i][0] - LEVEL_WIDTH)/SPRITE_WIDTH;
		x = nextPieceCoordinate[i][1]/SPRITE_WIDTH;
		
		if (x +  displacement < 0 || x + displacement > ROWS_OF_BOARD - 1) {//check if exceed the border
			moveable = false;
			break;
		} else if (board[x + displacement][y] != -1) {//check if the new cell is full
			moveable = false;
			break;
		}				
	}
	return moveable;
}

/**
 *Function: createReadyPiece
 *Purpose: create waiting piece
 *Var: nothing
 *Return: void
 **/
void createReadyPiece(){
	readyPieceType = randomChoice(NUMBER_OF_PIECE_TYPES);
	readyPieceRotation = randomChoice(4);
	readyieceColor = randomChoice(NUMBER_OF_COLORS);
	saveCoordinateOfNextPiece(320, 0, readyPieceType, readyPieceRotation);

	if (!(isAbleToSpawn(1))){
		gameOver = true;
	}
}

/**
 *Function: createNewPieces
 *Purpose: set up new info to new Piece from ready piece
 *Var: nothing
 *Return:void
 **/
void createNewPieces(){
	mPieceType = readyPieceType;
	mPieceRotation = readyPieceRotation;
	mColor = readyieceColor;
	srcX = 0;
	srcY = 0;
	dstX = 320;
	dstY = 0;
}

/**
 *Function: clearOldPositionInBoard
 *Purpose: - clear position of the previous piece
 *Var: nothing
 *Return: void
 **/
void clearOldPositionInBoard() {
	int x;
	int y;
	for (int i = 0; i < 4; i++){
		y = (pCoordinate[i][0] - LEVEL_WIDTH)/SPRITE_WIDTH;
		x = pCoordinate[i][1]/SPRITE_WIDTH;
		if (x >= 0 && y >= 0 && x <= ROWS_OF_BOARD - 1 && y <= COLS_OF_BOARD - 1)
			board[x][y] = -1; 
	}
}

/**
 *Function: applyOldPiecesToBoard()
 *Purpose: save info from old pieces
 *Var: nothing
 *Return: void
 **/
void applyOldPiecesToBoard(){
	int x;
	int y;
	for (int i = 0; i < 4; i++){
		y = (pCoordinate[i][0] - LEVEL_WIDTH)/SPRITE_WIDTH;
		x = pCoordinate[i][1]/SPRITE_WIDTH;
		if (x >= 0 && y >= 0 && x <= ROWS_OF_BOARD - 1 && y <= COLS_OF_BOARD - 1)
			board[x][y] = mColor; 
	}
}

/**
 *Function: isAbleToMoveDown
 *Purpose: check if the current piece can move down
 *Var: int: displacement
 *Return: true if success, otherwise return false
 **/
bool isAbleToMoveDown(int displacement) {
	bool moveable = true;
	int x,y;

	//clear the old position to try new position
	clearOldPositionInBoard();

	for (int i = 0; i < 4; i++) {
		y = (pCoordinate[i][0] - LEVEL_WIDTH)/SPRITE_WIDTH;
		x = pCoordinate[i][1]/SPRITE_WIDTH;
		
		if (x +  displacement < 0 || x + displacement > ROWS_OF_BOARD - 1) {//check if exceed the border
			moveable = false;
			break;
		} else if (board[x + displacement][y] != -1) {//check if the new cell is full
			moveable = false;
			break;
		}				
	}
	
	applyOldPiecesToBoard();

	return moveable;
}

/**
 *Function: isAbleToMoveLeftOrRight
 *Purpose: check if the current piece can move left or right
 *Var: int: displacement : 1 if move right, -1 if move left
 *Return: true if success, otherwise return false
 **/
bool isAbleToMoveLeftOrRight(int displacement) {
	bool moveable = true;
	int x,y;

	//clear the old position to try new position
	clearOldPositionInBoard();

	for (int i = 0; i < 4; i++) {
		y = (pCoordinate[i][0] - LEVEL_WIDTH)/SPRITE_WIDTH;
		x = pCoordinate[i][1]/SPRITE_WIDTH;
		
		//try the new position
		if (y + displacement < 0 || y + displacement > COLS_OF_BOARD - 1) { //check if exceed the border
			moveable = false;
			break;
		} else if (board[x][y + displacement] != -1) {//check if the new cell is full
			moveable = false;
			break;
		}				
	}

	// restore the old position
	applyOldPiecesToBoard();

	return moveable;
}

/**
 *Function: isRotateableOfLPiece
 *Purpose: check if the L piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateableOfLPiece() {
	bool rotateable = true;
	int currentState = mPieceRotation;
	int currentX = dstY/SPRITE_WIDTH;
	int currentY = (dstX-LEVEL_WIDTH)/SPRITE_WIDTH;
	
	//clear the old position to try new position
	clearOldPositionInBoard();

	switch (currentState) {
		case 0 : //change current state 0 to new state 1
			if (currentX+1 > ROWS_OF_BOARD - 1 || currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY-1] != -1 || board[currentX+1][currentY-1] != -1 || board[currentX][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		case 1 : //change current state 1 to new state 2
			if (currentX-1 < 0 || currentY-1 < 0 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX-1][currentY-1] != -1 || board[currentX+1][currentY] != -1) {
				rotateable = false;
			}
			break;
		case 2 : //change current state 2 to new state 3
			if (currentX-1 < 0 || currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY-1] != -1 || board[currentX][currentY+1] != -1 || board[currentX-1][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		case 3 : //change current state 3 to new state 0
			if (currentX-1 < 0 || currentY+1 > COLS_OF_BOARD - 1 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX+1][currentY] != -1 || board[currentX+1][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		default : break;
	}

	//restore the old position
	applyOldPiecesToBoard();

	return rotateable;
}

/**
 *Function: isRotateableOfJPiece
 *Purpose: check if the J piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateableOfJPiece() {
	bool rotateable = true;
	int currentState = mPieceRotation;
	int currentX = dstY/SPRITE_WIDTH;
	int currentY = (dstX-LEVEL_WIDTH)/SPRITE_WIDTH;
	
	//clear the old position to try new position
	clearOldPositionInBoard();

	switch (currentState) {
		case 0 : //change current state 0 to new state 1
			if (currentX-1 < 0 || currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY-1] != -1 || board[currentX][currentY-1] != -1 || board[currentX][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		case 1 : //change current state 1 to new state 2
			if (currentX-1 < 0 || currentY+1 > COLS_OF_BOARD - 1 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX-1][currentY+1] != -1 || board[currentX+1][currentY] != -1) {
				rotateable = false;
			}
			break;
		case 2 : //change current state 2 to new state 3
			if (currentX+1 > ROWS_OF_BOARD - 1 || currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY-1] != -1 || board[currentX][currentY+1] != -1 || board[currentX+1][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		case 3 : //change current state 3 to new state 0
			if (currentX-1 < 0 || currentY-1 < 0 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX+1][currentY] != -1 || board[currentX-1][currentY-1] != -1) {
				rotateable = false;
			}
			break;
		default : break;
	}

	//restore the old position
	applyOldPiecesToBoard();

	return rotateable;
}

/**
 *Function: isRotateableOfTPiece
 *Purpose: check if the T piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateableOfTPiece() {
	bool rotateable = true;
	int currentState = mPieceRotation;
	int currentX = dstY/SPRITE_WIDTH;
	int currentY = (dstX-LEVEL_WIDTH)/SPRITE_WIDTH;
	
	//clear the old position to try new position
	clearOldPositionInBoard();

	switch (currentState) {
		case 0 : //change current state 0 to new state 1
			if (currentX+1 > ROWS_OF_BOARD - 1 || currentY+1 > COLS_OF_BOARD - 1 || currentY-1 < 0) {
				rotateable = false;
			} else if (board[currentX][currentY-1] != -1 || board[currentX][currentY+1] != -1 || board[currentX+1][currentY] != -1) {
				rotateable = false;
			}
			break;
		case 1 : //change current state 1 to new state 2
			if (currentX-1 < 0 || currentY-1 < 0 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX][currentY-1] != -1 || board[currentX+1][currentY] != -1) {
				rotateable = false;
			}
			break;
		case 2 : //change current state 2 to new state 3
			if (currentX-1 < 0 || currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX][currentY-1] != -1 || board[currentX][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		case 3 : //change current state 3 to new state 0
			if (currentX+1 > ROWS_OF_BOARD - 1 || currentY+1 > COLS_OF_BOARD - 1 || currentX-1 < 0) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX][currentY+1] != -1 || board[currentX+1][currentY] != -1) {
				rotateable = false;
			}
			break;
		default : break;
	}

	//restore the old position
	applyOldPiecesToBoard();

	return rotateable;
}

/**
 *Function: isRotateableOfSPiece
 *Purpose: check if the S piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateableOfSPiece() {
	bool rotateable = true;
	int currentState = mPieceRotation;
	int currentX = dstY/SPRITE_WIDTH;
	int currentY = (dstX-LEVEL_WIDTH)/SPRITE_WIDTH;
	
	//clear the old position to try new position
	clearOldPositionInBoard();

	switch (currentState) {
		//change current state 0 or 2 to new state 1 or 3
		case 0 :
		case 2 :
			if (currentX+1 > ROWS_OF_BOARD - 1 || currentX-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX][currentY+1] != -1 || board[currentX+1][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		//change current state 1 or 3 to new state 0 or 2
		case 1 :
		case 3 :
			if (currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY+1] != -1 || board[currentX+1][currentY] != -1 || board[currentX+1][currentY-1] != -1) {
				rotateable = false;
			}
			break;
		default : break;
	}

	//restore the old position
	applyOldPiecesToBoard();

	return rotateable;
}

/**
 *Function: isRotateableOfZPiece
 *Purpose: check if the Z piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateableOfZPiece() {
	bool rotateable = true;
	int currentState = mPieceRotation;
	int currentX = dstY/SPRITE_WIDTH;
	int currentY = (dstX-LEVEL_WIDTH)/SPRITE_WIDTH;
	
	//clear the old position to try new position
	clearOldPositionInBoard();

	switch (currentState) {
		//change current state 0 or 2 to new state 1 or 3
		case 0 :
		case 2 :
			if (currentX+1 > ROWS_OF_BOARD - 1 || currentX-1 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY+1] != -1 || board[currentX-1][currentY+1] != -1 || board[currentX+1][currentY] != -1) {
				rotateable = false;
			}
			break;
		//change current state 1 or 3 to new state 0 or 2
		case 1 :
		case 3 :
			if (currentY-1 < 0 || currentY+1 > COLS_OF_BOARD - 1 || currentX+1 > ROWS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY-1] != -1 || board[currentX+1][currentY] != -1 || board[currentX+1][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		default : break;
	}

	//restore the old position
	applyOldPiecesToBoard();

	return rotateable;
}

/**
 *Function: isRotateableOfIPiece
 *Purpose: check if the I piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateableOfIPiece() {
	bool rotateable = true;
	int currentState = mPieceRotation;
	int currentX = dstY/SPRITE_WIDTH;
	int currentY = (dstX-LEVEL_WIDTH)/SPRITE_WIDTH;
	
	//clear the old position to try new position
	clearOldPositionInBoard();

	switch (currentState) {
		//change current state 0 or 2 to new state 1 or 3
		case 0 :
		case 2 :
			if (currentX+2 > ROWS_OF_BOARD - 1 || currentX-1 < 0) {
				rotateable = false;
			} else if (board[currentX-1][currentY] != -1 || board[currentX+1][currentY] != -1 || board[currentX+2][currentY] != -1) {
				rotateable = false;
			}
			break;
		//change current state 1 or 3 to new state 0 or 2
		case 1 :
		case 3 :
			if (currentY-2 < 0 || currentY+1 > COLS_OF_BOARD - 1) {
				rotateable = false;
			} else if (board[currentX][currentY-2] != -1 || board[currentX][currentY-1] != -1 || board[currentX][currentY+1] != -1) {
				rotateable = false;
			}
			break;
		default : break;
	}

	//restore the old position
	applyOldPiecesToBoard();

	return rotateable;
}

/**
 *Function: isRotateable
 *Purpose: check if the current piece can rotate or not
 *Var: nothing
 *Return: true if success, otherwise return false
 **/
bool isRotateable() {
	bool rotateable = false;

	switch (mPieceType) {//categorize the current piece
		case 1 : //the I piece
			if (isRotateableOfIPiece()) {
				rotateable = true;
			}
			break;
		case 2 : //the L piece
			if (isRotateableOfLPiece()) {
				rotateable = true;
			}
			break;
		case 3 : //the J piece
			if (isRotateableOfJPiece()) {
				rotateable = true;
			}
			break;
		case 4 : //the S piece
			if (isRotateableOfSPiece()) {
				rotateable = true;
			}
			break;
		case 5 : //the Z piece
			if (isRotateableOfZPiece()) {
				rotateable = true;
			}
			break;
		case 6 : //the T piece
			if (isRotateableOfTPiece()) {
				rotateable = true;
			}
			break;
		default : break;
	}

	return rotateable;		
}

/**
 *Function: updateDelayTime
 *Purpose: update the delay time when level upgrade
 *Var:nothing
 *Return: void
 **/
void updateDelayTime(){
	delayTime = 500 - 50*(mLevel - 2);
}

/**
 *Function: updatelevelCheckBoard
 *Purpose: update the level board to show level on screen
 *Var:nothing
 *Return: 1 if success, 0 if not.
 **/
int updatelevelCheckBoard(){
	int tmp = int(mScore/10) + 1;

	if (tmp != mLevel && tmp <= NUMBER_OF_LVLS) {
		mLevel = tmp;
		updateDelayTime();
		isLevelChange = true;
	}
	
	if (mLevel >= 0 && mLevel < NUMBER_OF_LVLS){
		levelCheckBoard[0] = 0;
		levelCheckBoard[1] = mLevel;
	} else if (mLevel == NUMBER_OF_LVLS){
		levelCheckBoard[0] = 1;
		levelCheckBoard[1] = 0;
	} else return 0;

	return 1;
}
/**
 *Function: updateScore()
 *Purpose: Update Score when full row
 *Var: nothing
 *Return:void
 **/
void updateScore(){
	mScore++;
}

/**
 *Function: updateScoreBoard
 *Purpose: update the score board to show score on screen
 *Var: nothing
 *Return: 1 if success, 0 if not.
 **/
int updateScoreBoard(){
	updateScore();

	if (mScore >= 0 && mScore < 10){
		scoreBoard[0] = 0;
		scoreBoard[1] = 0;
		scoreBoard[2] = mScore;
	} else if (mScore >= 10 && mScore <100) {
		scoreBoard[0] = 0;
		scoreBoard[1] = int(mScore/10);
		scoreBoard[2] = mScore%10;
	} else if (mScore >= 100 && mScore <1000){
		scoreBoard[0] = int(mScore/100);
		scoreBoard[1] = int((mScore%100)/10);
		scoreBoard[2] = mScore%10;
	} else return 0;

	return 1;
}

/**
 *Function: delFullRow()
 *Purpose: del full row out from the board
 *Var: fullRow: pivot of full row.
 *Return:void
 **/
void delFullRow(int fullRow){
	for (int i = fullRow; i > 0; i--){
		for(int j = 0; j < COLS_OF_BOARD; j++){
			board[i][j] = board[i-1][j];
		}
	}

	for(int j = 0; j < COLS_OF_BOARD; j++){
			board[0][j] = -1;
		}
}

/**
 *Function: checkFullRow()
 *Purpose: check a row full
 *Var: row: index of checking-row from board
 *Return:true if the row is full, false if not
 **/
bool checkFullRow(int row){
	for (int j = 0; j < COLS_OF_BOARD; j++){
		if (board[row][j] == -1) return false;
	}

	return true;
}

/**
 *Function: drawStarsAtFullRows()
 *Purpose: draw stars at every row full
 *Var: row: index of checking-row from board 
 **/
void drawStarsAtFullRows(int row){
	int pdstY = row*SPRITE_WIDTH;
	int pdstX = LEVEL_WIDTH;

	drawStaticImage(pdstX, pdstY, starAtFullRow, screen);		
}

/**
 *Function: checkBoard()
 *Purpose: check and del if any row full.
 *Var: nothing
 *Return:void
 **/
void checkBoard(){
	int i = ROWS_OF_BOARD - 1;

	while (i >= 0) {
		if (checkFullRow(i)) {
			isRowCuttable = true;
			spawnable = true;
			drawStarsAtFullRows(i);
		}
		i--;
	}

	i = ROWS_OF_BOARD - 1;
	while (i >= 0) {
		if (checkFullRow(i)) {
			delFullRow(i);
			if (!isMute) Mix_PlayChannel(-1, scratch, 0); // play scratch sound effect
			updateScoreBoard();
			updatelevelCheckBoard();
		}
		else i--;
	}
}

/**
 *Function: drawAllPiecesOnBoard()
 *Purpose: redraw all pieces on board.
 *Var: nothing
 *Return: void
 **/
void drawAllPiecesOnBoard() {
	for (int i = 0; i < ROWS_OF_BOARD; i++){
		for (int j = 0; j < COLS_OF_BOARD; j++){
			int pdstX = LEVEL_WIDTH + j*24;
			int pdstY = i*SPRITE_WIDTH;
			if (board[i][j] != -1){
				drawSprite(srcX,srcY,pdstX,pdstY,SPRITE_WIDTH,SPRITE_HEIGHT,spriteColor[board[i][j]],screen);
			}
			else{
				//drawSprite(srcX,srcY,pdstX,pdstY,SPRITE_WIDTH,SPRITE_HEIGHT,spriteGrid,screen);
			}
		}
	}
}

/**
 *Function: drawLevel()
 *Purpose: redraw level on board.
 *Var: nothing
 *Return: void
 **/
void drawLevel() {
	for (int i = 0; i < 2; i++) {
		int pdstX = LEVEL_X + i*NUMBER_WIDTH;
		int pdstY = LEVEL_Y;
		drawSprite(srcX,srcY,pdstX,pdstY,NUMBER_WIDTH,NUMBER_HEIGHT,numberR[levelCheckBoard[i]],screen);
	}
}

/**
 *Function: drawScore()
 *Purpose: redraw score on board.
 *Var: nothing
 *Return: void
 **/
void drawScore() {
	for (int i = 0; i < 3; i++){
		int pdstX = SCORE_X + i*NUMBER_WIDTH;
		int pdstY = SCORE_Y;
		drawSprite(srcX,srcY,pdstX,pdstY,NUMBER_WIDTH,NUMBER_HEIGHT,numberB[scoreBoard[i]],screen);
	}
}

/**
 *Function: drawButton()
 *Purpose: redraw button on board.
 *Var: nothing
 *Return: void
 **/
void drawButton(){
	drawSprite(srcX,srcY,buttonNewGame->bX,buttonNewGame->bY,buttonNewGame->bW,buttonNewGame->bH,spriteButtonNewGame,screen);
	drawSprite(srcX,srcY,buttonExitGame->bX,buttonExitGame->bY,buttonExitGame->bW,buttonExitGame->bH,spriteButtonExitGame,screen);
	drawSprite(srcX,srcY,buttonPauseGame->bX,buttonPauseGame->bY,buttonPauseGame->bW,buttonPauseGame->bH,spriteButtonPauseGame,screen);
	drawSprite(srcX,srcY,buttonSound->bX,buttonSound->bY,buttonSound->bW,buttonSound->bH,spriteButtonSound,screen);
}

/**
 *Function: restartGame()
 *Purpose: clear board and restart the game.
 *Var: nothing
 *Return:void
 **/
void restartGame(){
	gameOver = false;
	for(int i = 0; i < ROWS_OF_BOARD; i++)
		for(int j = 0; j < COLS_OF_BOARD; j++){
			board[i][j] = -1;
			SDL_Flip(screen);
			
		}
	dstX = 320;
	dstY = 0;

	//Init the score and level
	mScore = 0;
	mLevel = 1;

	//Init Delay Time
	delayTime = 600;

	//Init the score board:
	scoreBoard[0]=0;
	scoreBoard[1]=0;
	scoreBoard[2]=0;

	//Init the level board:
	levelCheckBoard[0]=0;
	levelCheckBoard[1]=1;

	createNewPieces();
	createReadyPiece();
}
/**
 *Function: handleKeyEvent
 *Purpose: Handle LEFT, RIGHT, UP, DOWN key event
 *Var: -event: var to control key Press
 *Return:void
 **/
void handleKeyEvent (SDL_Event event){
	switch (event.type){
		case SDL_QUIT: // Xed the window
			tetrisRunning = false;
			break;
		case SDL_KEYDOWN:
			switch (event.key.keysym.sym){
				case SDLK_DOWN: // press the DOWN key
					{
					int tmp = 1;
					bool stop = false;
					while (tmp < 19 && !stop){
						if (isAbleToMoveDown(tmp)){
							tmp++;
						}
						else stop = true;
					}
					clearOldPositionInBoard();
					dstY += (tmp-1)*SPRITE_HEIGHT;
					break;
					}
				case SDLK_UP: // press the UP key to rotate the piece
					if (isRotateable()) {
						clearOldPositionInBoard();

						if (mPieceRotation == 3){
							mPieceRotation = 0;
						} else { 
							mPieceRotation += 1;
						}
						if (!isMute) Mix_PlayChannel(-1, turn, 0);
						if (spawnable) { 
							spawnable = false; 
						}
					}
					break;
				case SDLK_LEFT: // press the LEFT key to move the piece left
					if (isAbleToMoveLeftOrRight(-1)) {
						clearOldPositionInBoard();
						dstX -= SPRITE_WIDTH;
						if (spawnable) { 
							spawnable = false; 
						}
					}
					break;
				case SDLK_RIGHT: // press the RIGHT key to move the piece right
					if (isAbleToMoveLeftOrRight(1)) {
						clearOldPositionInBoard();
						dstX += SPRITE_WIDTH;
						if (spawnable) { 
							spawnable = false; 
						}
					}
					break;
				case SDLK_ESCAPE:
					if (gameOver){
						tetrisRunning = false;
					}
					break;
				case SDLK_RETURN:
					if (gameOver){
						restartGame();
					}
					break;
				case SDLK_SPACE:
					gamePause = true;
					checkClock = SDL_GetTicks() - startClock;
					rwopButtonPauseGame = SDL_RWFromFile("bResume.png","rb");
					spriteButtonPauseGame = IMG_LoadPNG_RW(rwopButtonPauseGame);
					drawButton();
			}
			break;
	}
}
/**
 *Function: handleKeyEventResume
 *Purpose: Handle key event when pause
 *Var: -event: var to control key Press
 *Return:void
 **/
void handleKeyEventResume (SDL_Event event){
	switch (event.type){
		case SDL_QUIT: // Xed the window
			tetrisRunning = false;
			break;
		case SDL_KEYDOWN:
			switch (event.key.keysym.sym){
				case SDLK_SPACE:
					gamePause = false;
					startClock = SDL_GetTicks() - checkClock;
					rwopButtonPauseGame = SDL_RWFromFile("bPause.png","rb");
					spriteButtonPauseGame = IMG_LoadPNG_RW(rwopButtonPauseGame);
					drawButton();
			}
			break;
	}
}

/**
 *Function: handleMouseEvent
 *Purpose: Handle mouse event
 *Var: -event: var to control key Press
 *Return:void
 **/
void handleMouseEvent(SDL_Event event) {
	int x;
	int y;
	switch (event.type){
		case SDL_MOUSEBUTTONDOWN:
			x = event.button.x;
			y = event.button.y;
			if (event.button.button == SDL_BUTTON_LEFT){
				if( buttonNewGame->IsInside(x,y) ) restartGame();
				if( buttonExitGame->IsInside(x,y) ) tetrisRunning = false;
				if( buttonPauseGame->IsInside(x,y) ){
					if( !gamePause){
						gamePause = true;
						checkClock = SDL_GetTicks() - startClock;
						rwopButtonPauseGame = SDL_RWFromFile("bResume.png","rb");
						spriteButtonPauseGame = IMG_LoadPNG_RW(rwopButtonPauseGame);
						drawButton();
					}
					else {
						gamePause = false;
						startClock = SDL_GetTicks() - checkClock;
						rwopButtonPauseGame = SDL_RWFromFile("bPause.png","rb");
						spriteButtonPauseGame = IMG_LoadPNG_RW(rwopButtonPauseGame);
						drawButton();
					}
				}
				if( buttonSound->IsInside(x,y) ){
					if( !isMute){
						isMute = true;
						if( Mix_PausedMusic() != 1 ) Mix_PauseMusic();  
						rwopButtonSound = SDL_RWFromFile("bUnmute.png","rb");
						spriteButtonSound = IMG_LoadPNG_RW(rwopButtonSound);
						drawButton();
					}
					else {					
						isMute = false;
						if( Mix_PausedMusic() == 1 ) Mix_ResumeMusic(); 
						rwopButtonSound = SDL_RWFromFile("bMute.png","rb");
						spriteButtonSound = IMG_LoadPNG_RW(rwopButtonSound);
						drawButton();
					}
				}
			}
			break;
	}
}

/*************************************************************
 *Funtion: main
 *Purpose: Control all Tetris Game
 *************************************************************/
int main (int argc, char *args[]){
	//Init
	if(!init()){
		//Show Error dialog (Do later).
		return 0;
	}
	//Tetris Game Loop
	while (tetrisRunning) {
		if (!gamePause) {
			if (!gameOver) {
				if (!isMute){
					//Play theme music
					if (Mix_PlayingMusic() == 0) {
						Mix_PlayMusic(theme, -1);
					}
				}
				startClock = SDL_GetTicks(); //start timer
				//Handle input in fix time
				while(1) {
					fpsClock = SDL_GetTicks(); //start frame timer
					if(SDL_PollEvent(&event)){
						handleKeyEvent(event); //Handle Key Event
						handleMouseEvent(event); //Handle Mouse Event

						drawStaticImage(0,0,background[mLevel-1], screen); //Apply Surface
						drawAllPiecesOnBoard(); //Draw Sprite saved in board
						drawLevel(); //Draw Level
						drawScore(); //Draw Score
						drawButton(); //Draw Button

						//Draw Sprite of Ready Piece
						drawPieces(srcX,srcY,readyDstX,readyDstY,SPRITE_WIDTH,SPRITE_HEIGHT,
							spriteColor[readyieceColor],screen,readyPieceType,readyPieceRotation);
						//Draw Sprite of Current Piece
						drawPieces(srcX,srcY,dstX,dstY,SPRITE_WIDTH,SPRITE_HEIGHT,
							spriteColor[mColor],screen,mPieceType,mPieceRotation);

						//Sign Level Change
						if(isLevelChange){
							int levelIndex = mLevel - 1;
							drawStaticImage(LEVELSIGN_X,LEVELSIGN_Y,level[levelIndex], screen);
							SDL_Delay(500);
							isLevelChange = false;
						}
						SDL_Flip(screen); //Update The screen
						//Limit Frame
						if((SDL_GetTicks() - fpsClock) < 1000/FRAMES_PER_SECOND){
							SDL_Delay((1000/FRAMES_PER_SECOND) - (SDL_GetTicks() - fpsClock));
						}
					}
					//Check timer
					if (SDL_GetTicks() - startClock > delayTime) break;
				}
				drawStaticImage(0,0,background[mLevel-1], screen); //Apply Surface
				//Move piece down
				if (isAbleToMoveDown(1)){
					clearOldPositionInBoard(); 
					dstY += SPRITE_HEIGHT;
				}
				//Check board for full-row score
				if (spawnable) {
					drawAllPiecesOnBoard();	
					checkBoard();					
				}
				//Draw Sprite saved in board		
				if (!isRowCuttable) {
					drawAllPiecesOnBoard();					
				} else {
					isRowCuttable = false;				
				}
				drawLevel(); //Draw Level
				drawScore(); //Draw Score
				drawButton(); //Draw Button
				// if a new piece is about to spawn
				if (spawnable) {
					createNewPieces();	
					createReadyPiece();  
					spawnable = false;
				}		
				//Draw Sprite of Ready Piece
				drawPieces(srcX,srcY,readyDstX,readyDstY,SPRITE_WIDTH,SPRITE_HEIGHT,
					spriteColor[readyieceColor],screen,readyPieceType,readyPieceRotation);
				//Draw Sprite
				drawPieces(srcX,srcY,dstX,dstY,SPRITE_WIDTH,SPRITE_HEIGHT,
					spriteColor[mColor],screen,mPieceType,mPieceRotation);	

				//Check if a row cutting can be performed
				if (!(isAbleToMoveDown(1)) && !gameOver) {
					spawnable = true;
					//Save the position of current piece to board
					applyOldPiecesToBoard();	
				}
				//Sign Level Change
				if(isLevelChange){
					int levelIndex = mLevel - 1;
					drawStaticImage(LEVELSIGN_X,LEVELSIGN_Y,level[levelIndex], screen);
					SDL_Delay(500);
					isLevelChange = false;
				}
				SDL_Flip(screen); //Update The screen
			} else { // Handle Game Over

				drawStaticImage(GAMEOVER_X,GAMEOVER_Y,spriteGameOver, screen);
				if (SDL_PollEvent(&event)) {
					handleKeyEvent(event); //Handle Key Event
					handleMouseEvent(event); //Handle Mouse Event
				}
				SDL_Flip(screen); //Update screem
			}
		} else { // Handle Pause Game

			drawStaticImage(PAUSE_X,PAUSE_Y,spritePause, screen);
			if (SDL_PollEvent(&event)){
				handleKeyEventResume(event); //Handle Key Event Resume
				handleMouseEvent(event); //Handle Mouse Event
			}
			SDL_Flip(screen); //Update screem
		}
		//Limit Frame
		if((SDL_GetTicks() - startClock) < 1000/FRAMES_PER_SECOND){
			SDL_Delay((1000/FRAMES_PER_SECOND) - (SDL_GetTicks() - startClock));
		}
	}
	cleanup(); //Clean up
	SDL_Quit(); //Quit SDL

	return 0;
}